﻿// ———————————————————————–
// <copyright file="KMLStyleEngine.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// KMLStyleEngine.cs - Engine for loading available KML styles from a configuration file.
// Project: IC.NETSOA- KMLStyleEngine
//
// Language:    C#, .NET 4.0
// Platform:    Dell XPS m1530 Windows 7, VS 2010
// Author:      Brian Wilkins - Bedford
//              bwilkins@mitre.org, (781) 271-2332
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)

using System;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using EDXLCoT;
using EDXLSharp;
using EDXLSharp.EDXLDELib;
using EDXLSharp.EDXLHAVE_2_0Lib;
using EDXLSharp.NIEMCADLib;
using log4net;

namespace GISUtil.KML
{
  /// <summary>
  /// This class contains the methods used in loading the KML formatting styles from a configuration file. 
  /// </summary>
  public static class KMLStyleEngine
  {
    #region Private Member Variables

    /// <summary>
    /// Log4net logging object
    /// </summary>
    private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    /// <summary>
    /// The default style
    /// </summary>
    private static ICNETStyle DefaultStyle = new ICNETStyle()
    {
      Key = "DEFAULT",
      Style = new KMLStyle()
      {
        ID = "DEFAULT",
        FriendlyName = "Default KML Style",
        IconStyle = new IconStyle()
        {
          Icon = new KMLIcon()
          {
            href = "Incident_Other.png"
          }
        }
      }
    };

    /// <summary>
    /// CoT 9-1-1 special case
    /// </summary>
    private static KMLStyle Cot911Style = new KMLStyle()//Special case handling
    {
      ID = "CoT911",
      FriendlyName = "CoT 9-1-1",
      IconStyle = new IconStyle()
      {
        Icon = new KMLIcon()
        {
          href = "911.png"
        }
      }
    };

    
    private static ICNETStyleSet CADStyles;
    private static ICNETStyleSet CoTStyles;
    private static ICNETStyleSet HAVEStyles;
    private static ICNETStyleSet SitRepStyles;
    private static ICNETStyleSet TEPStyles;
    private static ICNETStyleSet RMStyles;
    private static ICNETStyleSet OtherStyles;

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes static members of the KMLStyleEngine class.
    /// </summary>
    static KMLStyleEngine()
    {
      LoadStyles();
    }
    #endregion

    #region Public Member Functions

    /// <summary>
    /// Gets the default style ID used in KML formatting.
    /// </summary>
    /// <returns>the default style ID in the form of a string.</returns>
    public static string DefaultStyleId
    {
      get
      {
        if (DefaultStyle == null)
        {
          return string.Empty;//TODO: Is this the best/correct way to handle null?
        }
        return @"#" + DefaultStyle.KMLStyleName;
      }
    }

    /// <summary>
    /// Gets the style to use for a content objects
    /// </summary>
    /// <param name="contentObject">Content object to look up the style for</param>
    /// <returns>The style for the content object</returns>
    internal static KMLStyle GetStyle(IContentObject contentObject)
    {
      ICNETStyle style = DefaultStyle;
      
      if (contentObject is CADEvent)
      {
        string key = ((CADEvent)contentObject).EventTypeDescriptor.TypeCode.Code.GetText();

        ICNETStyle s = CADStyles.GetStyleByKey(key);
        //if we didn't get a match, trim the type down until we do (or run out of type)
        while (s == null && key.Length > 0)
        {
          string[] keybits = key.Split('.');
          key = String.Join(".", keybits.Take(keybits.Length - 1));
          s = CADStyles.GetStyleByKey(key);
        }
        style = s;
      }
      else if (contentObject is CoTWrapper)
      {
        string key = ((CoTWrapper)contentObject).CoTEvent.Type;
        if (key.EndsWith("-9-1-1"))//Special case handling
        {
          return Cot911Style;
        }
        else
        {
          ICNETStyle s = CoTStyles.GetStyleByKey(key);
          //if we didn't get a match, trim the type down until we do (or run out of type)
          while (s == null && key.Length > 0)
          {
            string[] keybits = key.Split('-');
            key = String.Join("-", keybits.Take(keybits.Length - 1));
            s = CoTStyles.GetStyleByKey(key);
          }
          style = s;
        }
      }
      else if (contentObject is EDXLHAVE) //TODO: Do we want HAVE 1 or 2? Or both?
      {
        EDXLHAVE have = (EDXLHAVE)contentObject;
        HospitalType hospital = have.Hospital.FirstOrDefault();
        if (hospital != null) { /*do we have a variety of HAVE styles? if so, how do we key them?*/ }
        style = HAVEStyles.Styles.FirstOrDefault();
      }
      else if (contentObject is EDXLSharp.EDXLRMLib.ResourceMessageType)
      {
        style = RMStyles.Styles.FirstOrDefault();//TODO: RM KML style lookup
      }
      else if (contentObject is MEXLSitRepLib.SitRep)
      {
        MEXLSitRepLib.SitRep sitrep = (MEXLSitRepLib.SitRep)contentObject;
        if (sitrep.MessageReportType.HasValue)
        {
          style = SitRepStyles.GetStyleByKey(sitrep.MessageReportType.Value.ToString());
        }
      }
      
      return (style ?? DefaultStyle).Style;
    }


    internal static KMLStyle GetStyle(ContentObject contentObject)//does this need to be public?
    {
      if (contentObject == null)
      {
        return DefaultStyle.Style;
      }

      //TODO KMLStyleEngine.GetStyle (non-xml content object)
      throw new NotImplementedException();
    }


    /// <summary>
    /// Retrieves the style that matches the given ID
    /// </summary>
    /// <param name="Id">The KML name of the style</param>
    /// <returns>Returns the ICNETStyle or null if it cannot be found</returns>
    internal static ICNETStyle GetStyleFromId(string id) //does this need to be public?
    {
      if (id.StartsWith("#"))
      {
        id = id.Substring(1);
      }

      return CADStyles.GetStyleById(id) ??
             CoTStyles.GetStyleById(id) ??
             HAVEStyles.GetStyleById(id) ??
             SitRepStyles.GetStyleById(id) ??
             TEPStyles.GetStyleById(id) ??
             RMStyles.GetStyleById(id) ??
             OtherStyles.GetStyleById(id) ??
             DefaultStyle;
    }

    #endregion


    #region Private Member Functions

    /// <summary>
    /// Loads all of the styles from the KMLStyle.xml file. 
    /// </summary>
    private static void LoadStyles()
    {
      string icnetRoot = System.Environment.GetEnvironmentVariable("ICNET_ROOT", EnvironmentVariableTarget.Machine);

      if (icnetRoot == null)
      {
        Log.Warn("Missing ICNET_ROOT environment variable, defaulting to C:\\ICNET");
        icnetRoot = @"C:\ICNET";
      }

      XmlSerializer serializer = new XmlSerializer(typeof(ICNETStyleSet));
      string iconPath = @"\Resources";
      
      CADStyles = LoadStyles(icnetRoot + iconPath + @"\cadstyles.xml");
      Log.Info("Loaded " + CADStyles.Styles.Count + " CAD styles");

      CoTStyles = LoadStyles(icnetRoot + iconPath + @"\cotstyles.xml");
      Log.Info("Loaded " + CoTStyles.Styles.Count + " CoT styles");

      HAVEStyles = LoadStyles(icnetRoot + iconPath + @"\havestyles.xml");
      Log.Info("Loaded " + HAVEStyles.Styles.Count + " HAVE styles");

      SitRepStyles = LoadStyles(icnetRoot + iconPath + @"\sitrepstyles.xml");
      Log.Info("Loaded " + SitRepStyles.Styles.Count + " SitREp styles");

      TEPStyles = LoadStyles(icnetRoot + iconPath + @"\tepstyles.xml");
      Log.Info("Loaded " + TEPStyles.Styles.Count + " TEP styles");

      RMStyles = LoadStyles(icnetRoot + iconPath + @"\rmstyles.xml");
      Log.Info("Loaded " + RMStyles.Styles.Count + " RM styles");

      OtherStyles = LoadStyles(icnetRoot + iconPath + @"\defaultstyles.xml");
    }

    private static ICNETStyleSet LoadStyles(string path)
    {
      try
      {
        XmlSerializer serializer = new XmlSerializer(typeof(ICNETStyleSet));
        using (StreamReader reader = new StreamReader(path))
        {
          return (ICNETStyleSet)serializer.Deserialize(reader);
        }
      }
      catch (Exception ex)
      {
        Log.Error("KMLStyleEngine - An Error occurred loading styles from " + path, ex);
        return new ICNETStyleSet();
      }
    }
    #endregion
  }
}